﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Xrm.Sdk;

namespace EasyCRM
{
    public class EntityManager
    {
        public Entity Entity
        {
            get;
            set;
        }

        #region Constructors
        public EntityManager ()
        {
        }

        public EntityManager (Entity entity)
        {
            this.Entity = entity;
        } 
        #endregion

        #region Normal methods
        public dynamic GetValue (string field)
        {
            return EntityManager.GetValue(this.Entity, field);
        }

        public List<object> GetValues (string[] fields)
        {
            return EntityManager.GetValues(this.Entity, fields);
        }

        public void SetValue (string field, object value)
        {
            EntityManager.SetValue(this.Entity, field, value);
        }

        public void SetValue (List<KeyValuePair<string, object>> values)
        {
            EntityManager.SetValues(this.Entity, values);
        }
        #endregion

        #region Static methods
        public static dynamic GetValue (Entity entity, string field)
        {
            if ( entity.Contains(field) )
            {
                Type typeEntityManager = entity[field].GetType();

                switch ( typeEntityManager.Name )
                {
                    case "String":
                        return EntityManager.Cast<string>(entity[field]);
                    case "Int":
                        return EntityManager.Cast<int>(entity[field]);
                    case "Decimal":
                        return EntityManager.Cast<decimal>(entity[field]);
                    case "Double":
                        return EntityManager.Cast<double>(entity[field]);
                    case "OptionSetValue":
                        return EntityManager.Cast<OptionSetValue>(entity[field]);
                    case "Guid":
                        return EntityManager.Cast<Guid>(entity[field]);
                    case "EntityReference":
                        return EntityManager.Cast<EntityReference>(entity[field]);
                    case "Money":
                        return EntityManager.Cast<Money>(entity[field]);
                    case "DateTime":
                        return EntityManager.Cast<DateTime>(entity[field]);
                    default:
                        throw new Exception("Attribute is not a valid CRM type.");
                }
            }
            else
            {
                throw new Exception("Entity has not any field called " + field + ".");
            }
        }

        public static List<object> GetValues (Entity entity, string[] fields)
        {
            List<dynamic> values = new List<dynamic>();

            try
            {
                Array.ForEach<string>(fields, (f) =>
                {
                    values.Add(EntityManager.GetValue(entity, f));
                });
            }
            catch ( Exception ex )
            {
                throw new Exception("An error occurs obtaining values.", ex);
            }

            return values;
        }

        public static void SetValue (Entity entity, string field, object value)
        {
            if ( entity.Contains(field) )
            {
                entity[field] = value;
            }
            else
            {
                entity.Attributes.Add(field, value);
            }
        }

        public static void SetValues (Entity entity, List<KeyValuePair<string, object>> values)
        {
            try
            {
                foreach ( var kvp in values )
                {
                    EntityManager.SetValue(entity, kvp.Key, kvp.Value);
                }
            }
            catch ( Exception ex )
            {
                throw new Exception("An error occurs setting values.", ex);
            }
        }

        public static T Cast<T> (object o)
        {
            return (T)o;
        }

        public static bool Compare (object value1, object value2)
        {
            if ( value1 == value2 )
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion
    }
}